JavaScript ES6 以後加入了 ”箭頭函式“,就外觀看來它就像是一個縮寫,也因此許多新手會認為它是屬於傳統函式的縮寫形式;但其實不然,箭頭函式與傳統函式大不同,本篇僅列出最常見的 this
差異,並透過大量的範例題,並透過範例的方式讓新手避免踩到箭頭函式最常見的雷。
JS 中很常利用物件、方法的形式來建構組件,在物件中的方法也可透過 this 來取得物件中的其它屬性。
不過傳統函式中 this 的指向是隨著呼叫的方式不同而定,以下方的範例來說預期會一一列出 "XXX 是小明的朋友",但因爲列出陣列是使用 forEach
方法,其中包含了一個 callback function,所以指向也因此有所變化。
const Ming = {
myName: '小明',
friends: ['漂亮阿姨', '杰倫', '小美'],
getFriends() {
this.friends.forEach(function(friend) {
console.log(`${friend} 是 ${this.myName} 的朋友`);
});
}
}
Ming.getFriends();
this 的指向因為外層的 callback function
而轉為 全域
,所以最終的都列出 undefined
的結果。
漂亮阿姨 是 undefined 的朋友
杰倫 是 undefined 的朋友
小美 是 undefined 的朋友
箭頭函式最大的特點就是沒有自己的 this
,因此當箭頭函式中出現了 this
,它則會指向外層的作用域所對應的 this
。
以下範例來 this.myName
的值就能夠正確指向此物件,迴圈的值也會如預期產生。
const Ming = {
myName: '小明',
friends: ['漂亮阿姨', '杰倫', '小美'],
getFriends() {
this.friends.forEach(friend => {
console.log(`${friend} 是 ${this.myName} 的朋友`);
});
}
}
Ming.getFriends();
重點:因為箭頭函式沒有自己的 this
,所以要找到箭頭函式的 this
指向時,可直接參考其外層作用域的 this
指向。關於 this 的指向可參考 this 與物件的關係。
透過箭頭函式可不需要調整太多結構,就能使 this
的指向符合預期。
漂亮阿姨 是 小明 的朋友
杰倫 是 小明 的朋友
小美 是 小明 的朋友
只有看介紹,難以確定觀念是否正確,所以以下補上相關題目給大家練習練習。
首先,外層都會先宣告 myName = '全域'
,所以以下題目需了解最終 this
是指向全域或區域的變數。
var myName = '全域';
以下的結果為:
var Ming = {
myName: '小明',
fn() {
setTimeout(() => {
console.log(this.myName);
}, 0);
}
};
Ming.fn();
.
.
.
.
.
.
.
.
這題結構與一開始所介紹的其實是相同的,請記得箭頭函式沒有自己的 this
,請向外層作用域尋找,因此會找到 fn()
這個傳統函式,在對應到 Ming.fn()
,所以 this
會指向 Ming
,結果為 1. 小明。
以下的結果為:
var Ming = {
myName: '小明',
fn:() => {
console.log(this.myName);
}
};
Ming.fn();
.
.
.
.
.
.
.
.
.
實戰中,如果物件內的方法會用到 this
,都會避免將該方法使用箭頭函式來建立,因為此時的 this
指向是外層的作用域,相對來說外層的作用域將更難以確立。
在此外層的作用域是直接對應全域,所以此題的結果為 2. 全域。
以下的結果為:
var Ming = {
myName: '小明',
family: {
myName: '小明家',
fn: ()=> {
console.log(this.myName);
}
}
};
Ming.family.fn();
.
.
.
.
.
.
.
.
.
此題的概念與上一題相同,雖然物件有多個層級,但在此也是直接查找最外層的最用域 this
指向,因此答案依然為 2. 全域。
以下的結果為:
(function () {
var myName = '立即函式作用域';
var Ming = {
myName: '小明',
fn:() => {
console.log(this.myName);
}
};
Ming.fn();
})();
.
.
.
.
.
.
.
.
.
.
這題是陷阱題,立即函式屬於 simple call
,this
是指向全域。
(function () {
console.log(this === window); // 立即函式的 this 與全域相同
})();
因此本題的答案依然為 2. 全域。
以下的結果為:
var Ming = {
myName: '小明',
family: {
myName: '小明家',
fn: ()=> {
(function() {
console.log(this.myName);
})();
}
}
};
Ming.family.fn();
.
.
.
.
.
.
.
.
.
如果這題會錯可能是題目做太多被搞混了,請仔細思考一下這題的 this
由誰而定。
本題的 this
是由立即函式決定,因此是指向 2. 全域。
實戰中通常也不會那麼的複雜,只要清楚箭頭沒有自己的 this
,外層的作用域 this 是什麼,它就是什麼。
為了避免箭頭函式在實戰中出錯,可以有以下幾個方法:
this
指向只要搞懂箭頭函式的 this
,也就盡情的使用箭頭函式,並嘗試使用其縮寫來大幅減少程式碼喔。